package jeye.lcdui;

import java.io.InputStream;

import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;
import javax.microedition.lcdui.game.GameCanvas;
import javax.microedition.lcdui.game.Sprite;

import jeye.client.buffer.FrameBuffer;
import jeye.client.thread.FrameBufferThread;
import jeye.client.thread.RunnablePlayer;
import jeye.lcdui.util.HttpServiceSupport;
import jeye.lcdui.util.ScreenFactorySupport;
import jeye.midlet.ApplicationController;
import jeye.midlet.ScreenType;
import jeye.util.HttpConnector;

public class CameraPreview extends GameCanvas implements RunnablePlayer, CommandListener, ScreenFactorySupport, HttpServiceSupport {
	
	private ApplicationController controller;
	
	private boolean paintFlag = false;
	
	private Image image;
	
	private FrameBuffer buffer = new FrameBuffer();
	
	private FrameBufferThread bufferThread;
	
	private static final int FRAMERATE = 15;
	
	private Command startCommand = new Command("Odtwarzaj", Command.ITEM, 1);
	
	private Command backCommand = new Command("Wstecz", Command.BACK, 2);
	
	private HttpConnector connector;
	
	private Float quality;
	
	private int frameSkip = 1;
	
	private Long eventId;
	
	public CameraPreview() {
		super(true);
	}
	
	public void run() {
		try {
			while(true) {
				InputStream stream = buffer.getFrame();
				
				if(stream != null) {
					image = Image.createImage(stream);
					paintFlag = true;
					repaint();
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	private Image deinterlace(Image source) {
		int height = source.getHeight();
		int width = source.getWidth();
		Image result = Image.createImage(width, height*2);
		Graphics g = result.getGraphics();
		int j = -1;
		
		for(int i=0;i<height;i++) {
			g.drawRegion(source, 0, i, width, 1, Sprite.TRANS_NONE , 0, j++, Graphics.TOP | Graphics.LEFT);
			g.drawRegion(source, 0, i, width, 1, Sprite.TRANS_NONE , 0, j++, Graphics.TOP | Graphics.LEFT);
		}
		
		return result;
	}
	
	private Image resizeImage(Image src, int screenWidth, int screenHeight) {
	      int srcWidth = src.getWidth();
	      int srcHeight = src.getHeight();
	      Image tmp = Image.createImage(screenWidth, srcHeight);
	      Graphics g = tmp.getGraphics();
	      int ratio = (srcWidth << 16) / screenWidth;
	      int pos = ratio/2;

	      //Horizontal Resize        

	      for (int x = 0; x < screenWidth; x++) {
	          g.setClip(x, 0, 1, srcHeight);
	          g.drawImage(src, x - (pos >> 16), 0, Graphics.LEFT | Graphics.TOP);
	          pos += ratio;
	      }

	      Image resizedImage = Image.createImage(screenWidth, screenHeight);
	      g = resizedImage.getGraphics();
	      ratio = (srcHeight << 16) / screenHeight;
	      pos = ratio/2;        

	      //Vertical resize

	      for (int y = 0; y < screenHeight; y++) {
	          g.setClip(0, y, screenWidth, 1);
	          g.drawImage(tmp, 0, y - (pos >> 16), Graphics.LEFT | Graphics.TOP);
	          pos += ratio;
	      }
	      return resizedImage;

	  }

	public void paint(Graphics g) {
		super.paint(g);
		g.setColor(0x000000);
		g.fillRect(0, 0, getWidth(), getHeight());

		if(paintFlag) {
//			Image image = deinterlace(this.image, this.image.getWidth()*2, this.image.getHeight()*2);
			Image image = resizeImage(this.image, this.image.getWidth()*2, this.image.getHeight()*2);

			long t1 = System.currentTimeMillis();
			int x = (getWidth() - image.getWidth()) / 2;
			int y = (getHeight() - image.getHeight()) / 2;
			
			g.drawImage(image, x, y, Graphics.TOP | Graphics.LEFT);
			
			long frameTime = getFrameTime();
			long time = System.currentTimeMillis() - t1;
			
			try {
				Thread.sleep(frameTime - time);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		} 
		if(bufferThread.isBuffering()){
			g.setColor(0xFFFFFF);
			g.drawString("Buffering... " + bufferThread.getPercentComplete() + "%", 5, 0, Graphics.TOP | Graphics.LEFT);
		}
	}

	public long getFrameTime() {
		return 1000 / (FRAMERATE / bufferThread.getFrameSkip());
	}

	public void repaintPlayer() {
		repaint();
	}

	public void commandAction(Command command, Displayable displayable) {
		if(command.equals(startCommand)) {
			play();
		}
		else if(command.equals(backCommand)) {
			controller.setCurrentDisplay(ScreenType.EVENTS_LIST);
		}
	}
	
	public void setFrameSkip(int frameSkip) {
		this.frameSkip = frameSkip;
	}
	
	public int getFrameSkip() {
		return frameSkip;
	}
	
	public void setQuality(Float quality) {
		this.quality = quality;
	}
	
	public Float getQuality() {
		return quality;
	}

	public void initialize() {
		addCommand(startCommand);
		addCommand(backCommand);
		
		setCommandListener(this);
	}

	public void setController(ApplicationController controller) {
		this.controller = controller;
	}

	public void setHttpConnector(HttpConnector connector) {
		this.connector = connector;
	}
	
	public void play() {
		bufferThread = new FrameBufferThread(connector, buffer, eventId, this);
		
		bufferThread.setScreenWidth(new Integer(getWidth()/2));
		bufferThread.setScreenHeight(new Integer(getHeight()/2));
		bufferThread.setFrameSkip(frameSkip);
		bufferThread.setQuality(quality);
		bufferThread.start();
	}

	public Long getEventId() {
		return eventId;
	}

	public void setEventId(Long eventId) {
		this.eventId = eventId;
	}
	
}
